package cn.okcode.api.framework.dispatcher;

import cn.okcode.api.framework.ActionException;
import cn.okcode.api.framework.annotation.CPController;
import cn.okcode.api.framework.annotation.CPService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;


/**
 * @author pyk13
 */
public class BeanDefinitionReader {

    public static final Logger logger = LogManager.getLogger(BeanDefinitionReader.class.getName());

    private final List<String> beanClassNames = new ArrayList<>();

    public BeanDefinitionReader(String... scanPackages) {
        doScanner(scanPackages);
    }

    public BeanDefinitionReader(String jatPath, String... scanPackages) {
        doJarScanner(jatPath, scanPackages);
    }

    private void doJarScanner(String jarPath, String... scanPackages) {
        if (logger.isDebugEnabled()) {
            logger.debug("jarPath:" + jarPath);
        }
        beanClassNames.clear();
        final String CLASS_SUFFIX = ".class";
        File jarFile = new File(jarPath);
        try (JarFile jar = new JarFile(jarFile)) {
            Enumeration<JarEntry> entries = jar.entries();
            int count = 0;
            while (entries.hasMoreElements()) {
                count++;
                JarEntry entry = entries.nextElement();
                String entryName = entry.getName().replaceAll("/", ".");
                if (!entryName.endsWith(CLASS_SUFFIX)) {
                    continue;
                }
                for (String packageName : scanPackages) {
                    if (entryName.startsWith(packageName)) {
                        // 在这里处理找到的类文件
                        System.out.println("Found class file: " + entryName);
                        beanClassNames.add(entryName.substring(0, entryName.length() - CLASS_SUFFIX.length()));
                    }
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("count:" + count);
            }
        } catch (IOException e) {
            throw new ActionException("打开jar包出错,jar路径：" + jarPath);
        }
    }

    private void doScanner(String... scanPackages) {
        beanClassNames.clear();
        for (String scanPackage : scanPackages) {
            URL url = this.getClass().getResource("/" + scanPackage.replaceAll("\\.", "/"));
            if (url == null) {
                logger.error("scanPackage(" + scanPackage + ")不是有效值");
                continue;
            }
            File classPath = new File(url.getFile());
            for (File file : classPath.listFiles()) {
                if (file.isDirectory()) {
                    doScanner(scanPackage + "." + file.getName());
                } else {
                    if (!file.getName().endsWith(".class")) {
                        continue;
                    }
                    String className = (scanPackage + "." + file.getName().replace(".class", ""));
                    beanClassNames.add(className);
                }
            }
        }
    }

    public List<BeanDefinition> loadBeanDefinitions() {
        List<BeanDefinition> result = new ArrayList<>();
        for (String className : beanClassNames) {
            Class<?> beanClass;
            try {
                beanClass = Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new ActionException("初始化类出错,找不到名称为" + className + "的类", e);
            }
            if (beanClass.isInterface()) {
                continue;
            }
            if (!Modifier.isPublic(beanClass.getModifiers()) || Modifier.isStatic(beanClass.getModifiers())) {
                continue;
            }
            //判断只有加了注解的类，才进行实例化
            if (!(beanClass.isAnnotationPresent(CPController.class) || beanClass.isAnnotationPresent(CPService.class))) {
                continue;
            }
            result.add(doCreateBeanDefinition(beanClass.getName(), beanClass.getName()));

            Class<?>[] interfaces = beanClass.getInterfaces();
            for (Class<?> i : interfaces) {
                result.add(doCreateBeanDefinition(i.getName(), beanClass.getName()));
            }
        }
        return result;
    }

    private BeanDefinition doCreateBeanDefinition(String factoryBeanName, String beanClassName) {
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanClassName(beanClassName);
        beanDefinition.setFactoryBeanName(factoryBeanName);
        return beanDefinition;
    }
}
